fix: Day2就绪 — 删除硬化+索引补全+全局异常处理
## base_service.py — MaterialBase删除硬化 - 新增 BomTable 引用检查(bom_usage_count) - 物料被BOM引用时禁止删除,提示「请先解除BOM绑定」 ## models/base.py + bom.py — 缺失索引补全 - material_base: company_name + is_enabled 添加 index=True - bom_table: is_enabled 添加 index=True ## __init__.py — 全局异常处理 - @app.errorhandler(ValueError) → 400 + 自定义消息 - @app.errorhandler(404/405) → 标准错误 - @app.errorhandler(Exception) → 500 + 通用消息 堆栈仅记录服务器日志,不泄露到前端
This commit is contained in:
@ -1,6 +1,6 @@
|
|||||||
# 文件路径: inventory-backend/app/__init__.py
|
# 文件路径: inventory-backend/app/__init__.py
|
||||||
|
|
||||||
from flask import Flask
|
from flask import Flask, jsonify
|
||||||
from config import Config
|
from config import Config
|
||||||
from app.extensions import db, migrate, cors, jwt
|
from app.extensions import db, migrate, cors, jwt
|
||||||
from app.api.v1.scan import scan_bp
|
from app.api.v1.scan import scan_bp
|
||||||
@ -295,4 +295,33 @@ def create_app():
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"⚠️ 模型预加载发生未知错误: {e}")
|
print(f"⚠️ 模型预加载发生未知错误: {e}")
|
||||||
|
|
||||||
|
# =========================================================
|
||||||
|
# 4. 全局异常处理(面向生产:不泄露堆栈)
|
||||||
|
# =========================================================
|
||||||
|
import logging
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
@app.errorhandler(ValueError)
|
||||||
|
def handle_value_error(e):
|
||||||
|
"""业务校验异常 → 400 + 自定义消息"""
|
||||||
|
return jsonify({'code': 400, 'msg': str(e)}), 400
|
||||||
|
|
||||||
|
@app.errorhandler(404)
|
||||||
|
def handle_not_found(e):
|
||||||
|
return jsonify({'code': 404, 'msg': '资源不存在'}), 404
|
||||||
|
|
||||||
|
@app.errorhandler(405)
|
||||||
|
def handle_method_not_allowed(e):
|
||||||
|
return jsonify({'code': 405, 'msg': '请求方法不允许'}), 405
|
||||||
|
|
||||||
|
@app.errorhandler(Exception)
|
||||||
|
def handle_unhandled_exception(e):
|
||||||
|
"""兜底:任何未捕获异常 → 500 + 通用消息,堆栈仅记录日志"""
|
||||||
|
app.logger.error(f"Unhandled exception: {type(e).__name__}: {e}\n{traceback.format_exc()}")
|
||||||
|
return jsonify({
|
||||||
|
'code': 500,
|
||||||
|
'msg': '系统繁忙,请稍后再试',
|
||||||
|
'error': 'Internal Server Error'
|
||||||
|
}), 500
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
|||||||
@ -13,7 +13,7 @@ class MaterialBase(db.Model):
|
|||||||
|
|
||||||
# 1. 基础字段
|
# 1. 基础字段
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
company_name = db.Column(db.String(255), comment='所属公司')
|
company_name = db.Column(db.String(255), index=True, comment='所属公司') # ★ 多租户过滤高频列
|
||||||
|
|
||||||
name = db.Column(db.String(255), nullable=False, index=True, comment='名称') # ★ 模糊搜索/精确定位高频列
|
name = db.Column(db.String(255), nullable=False, index=True, comment='名称') # ★ 模糊搜索/精确定位高频列
|
||||||
common_name = db.Column(db.String(255), comment='俗名')
|
common_name = db.Column(db.String(255), comment='俗名')
|
||||||
@ -34,7 +34,7 @@ class MaterialBase(db.Model):
|
|||||||
manual_link_remark = db.Column(db.Text, default='', comment='说明书备注')
|
manual_link_remark = db.Column(db.Text, default='', comment='说明书备注')
|
||||||
|
|
||||||
# 启用状态
|
# 启用状态
|
||||||
is_enabled = db.Column(db.Boolean, default=True, comment='是否启用')
|
is_enabled = db.Column(db.Boolean, default=True, index=True, comment='是否启用') # ★ 状态过滤高频列
|
||||||
|
|
||||||
# 强制质检标记(采购入库时必须上传检测报告)
|
# 强制质检标记(采购入库时必须上传检测报告)
|
||||||
is_inspection_required = db.Column(db.Boolean, default=False, comment='是否强制要求质检')
|
is_inspection_required = db.Column(db.Boolean, default=False, comment='是否强制要求质检')
|
||||||
|
|||||||
@ -26,7 +26,7 @@ class BomTable(db.Model):
|
|||||||
remark = db.Column(db.Text, comment='备注')
|
remark = db.Column(db.Text, comment='备注')
|
||||||
|
|
||||||
# ★ 新增:启用状态
|
# ★ 新增:启用状态
|
||||||
is_enabled = db.Column(db.Boolean, default=True, comment='是否启用')
|
is_enabled = db.Column(db.Boolean, default=True, index=True, comment='是否启用') # ★ 状态过滤高频列
|
||||||
|
|
||||||
# 约束: 保证同一版本下的父子对唯一,允许不同版本存在
|
# 约束: 保证同一版本下的父子对唯一,允许不同版本存在
|
||||||
__table_args__ = (
|
__table_args__ = (
|
||||||
|
|||||||
@ -7,6 +7,7 @@ from app.models.inbound.buy import StockBuy
|
|||||||
from app.models.inbound.semi import StockSemi
|
from app.models.inbound.semi import StockSemi
|
||||||
from app.models.inbound.product import StockProduct
|
from app.models.inbound.product import StockProduct
|
||||||
# from app.models.inbound.service import StockService
|
# from app.models.inbound.service import StockService
|
||||||
|
from app.models.bom import BomTable
|
||||||
from sqlalchemy import or_, and_, func, case, desc, asc, cast, Numeric, text
|
from sqlalchemy import or_, and_, func, case, desc, asc, cast, Numeric, text
|
||||||
import traceback
|
import traceback
|
||||||
import json
|
import json
|
||||||
@ -746,8 +747,11 @@ class MaterialBaseService:
|
|||||||
buy_usage_count = StockBuy.query.filter_by(base_id=m_id).count()
|
buy_usage_count = StockBuy.query.filter_by(base_id=m_id).count()
|
||||||
semi_usage_count = StockSemi.query.filter_by(base_id=m_id).count()
|
semi_usage_count = StockSemi.query.filter_by(base_id=m_id).count()
|
||||||
prod_usage_count = StockProduct.query.filter_by(base_id=m_id).count()
|
prod_usage_count = StockProduct.query.filter_by(base_id=m_id).count()
|
||||||
|
bom_usage_count = BomTable.query.filter(
|
||||||
|
or_(BomTable.parent_id == m_id, BomTable.child_id == m_id)
|
||||||
|
).count()
|
||||||
|
|
||||||
total_usage = buy_usage_count + semi_usage_count + prod_usage_count
|
total_usage = buy_usage_count + semi_usage_count + prod_usage_count + bom_usage_count
|
||||||
|
|
||||||
if total_usage > 0:
|
if total_usage > 0:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
@ -755,7 +759,8 @@ class MaterialBaseService:
|
|||||||
f"- 采购库存记录: {buy_usage_count} 条\n"
|
f"- 采购库存记录: {buy_usage_count} 条\n"
|
||||||
f"- 半成品库存记录: {semi_usage_count} 条\n"
|
f"- 半成品库存记录: {semi_usage_count} 条\n"
|
||||||
f"- 成品库存记录: {prod_usage_count} 条\n"
|
f"- 成品库存记录: {prod_usage_count} 条\n"
|
||||||
f"请先清理相关库存或仅‘禁用’此条目。"
|
f"- BOM配方引用: {bom_usage_count} 条\n"
|
||||||
|
f"请先清理相关库存/BOM绑定或仅「禁用」此条目。"
|
||||||
)
|
)
|
||||||
|
|
||||||
# 删除时同步清理向量记录
|
# 删除时同步清理向量记录
|
||||||
|
|||||||
Reference in New Issue
Block a user