fix(product): 删除引用保护/单价小数位校验,IntegrityError 全局兜底转 400
- delete_product 补 count_refs 引用检查(业务明细+发货明细 RESTRICT 外键)与并发窗口 IntegrityError→400 兜底(customer 先例同构), docstring 与两个 api 层过时注释同步更新 - 产品 schema 复用 schemas/business._check_amount:sale_price 走 (PRICE_MAX, scale=4)、stock_quantity 走 AMOUNT_MAX——此前私写 _parse_non_negative 不查小数位与容量,5 位小数被 Numeric(14,4) 静默截断(舍入即算错钱);新增 6 个秒级 schema 单测锁定口径 - 全局注册 IntegrityError handler:漏补引用保护的删除类操作收敛为 400 通用文案(e2e 撞见一个补一个的模式无法保证全覆盖),完整 异常记日志;rating/customer 的「非 1062 按 500」注释同步更正 Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
1 parent
9a70264b51
commit
91fc6f6293
11 files changed
+243
-40
No files matched your search
@@ -12,6 +12,7 @@ import logging
|
||||
from fastapi import FastAPI, Request
|
||||
from fastapi.exceptions import RequestValidationError
|
||||
from fastapi.responses import JSONResponse
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
from starlette.exceptions import HTTPException as StarletteHTTPException
|
||||
|
||||
from app.core.constants import CODE_BAD_REQUEST, CODE_SERVER_ERROR
|
||||
@@ -60,6 +61,19 @@ async def handle_http_exception(_: Request, exc: StarletteHTTPException) -> JSON
|
||||
return _build_response(exc.status_code, message)
|
||||
|
||||
|
||||
async def handle_integrity_error(_: Request, exc: IntegrityError) -> JSONResponse:
|
||||
"""完整性错误全局兜底为 400。
|
||||
|
||||
service 层已判别的 1062/引用冲突会自行翻译为业务提示,不会走到这里;
|
||||
本 handler 拦截的是「新增父表后某 service 漏补引用保护」一类的遗漏
|
||||
(e2e 撞见一个补一个的模式无法保证全覆盖):FK RESTRICT 等数据完整性
|
||||
冲突对用户表现为「这行数据被别处引用/冲突」,转 400 比 500 更贴近事实。
|
||||
完整异常记录日志供排查;不在此处 rollback —— 会话由请求级依赖统一关闭。
|
||||
"""
|
||||
logger.error("数据库完整性冲突(未在 service 层翻译)", exc_info=exc)
|
||||
return _build_response(CODE_BAD_REQUEST, "数据完整性冲突,操作被拒绝")
|
||||
|
||||
|
||||
async def handle_unexpected_exception(_: Request, exc: Exception) -> JSONResponse:
|
||||
"""兜底处理未预期异常。
|
||||
|
||||
@@ -77,4 +91,5 @@ def register_exception_handlers(app: FastAPI) -> None:
|
||||
app.add_exception_handler(AppException, handle_app_exception) # type: ignore[arg-type]
|
||||
app.add_exception_handler(RequestValidationError, handle_validation_error) # type: ignore[arg-type]
|
||||
app.add_exception_handler(StarletteHTTPException, handle_http_exception) # type: ignore[arg-type]
|
||||
app.add_exception_handler(IntegrityError, handle_integrity_error) # type: ignore[arg-type]
|
||||
app.add_exception_handler(Exception, handle_unexpected_exception)
|
||||
Reference in new issue
Block a user