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:
liuwenxinandClaude Code committed 2026-10-14 18:48:32 +08:00
1 parent 9a70264b51
commit 91fc6f6293
11 files changed
+243 -40

No files matched your search

+72
View File
@@ -0,0 +1,72 @@
"""产品 schema 的金额口径单测(秒级,无外部依赖)。
守:产品 sale_price/stock_quantity 若私写校验不查小数位与容量,5 位小数
会被 Numeric 列静默截断(舍入即算错钱)、超容量会以 500 暴露 —— 校验
口径必须与 schemas/business._check_amount 一致(shipment/receipt 同源)。
"""
import pytest
from pydantic import ValidationError
from app.schemas.product import ProductCreateIn
class TestSalePrice:
"""单价校验:scale=4 对齐 Numeric(14,4) 列。"""
def test_四位小数通过_回显原样提交(self) -> None:
"""带精度的历史单价必须能原样提交(fba8cfc 教训:编辑被永远拒收)。"""
body = ProductCreateIn(
product_name="t_产品",
product_category="municipal_water",
sale_price="5000.1234",
)
assert body.sale_price == "5000.1234"
def test_五位小数拒绝而非静默截断(self) -> None:
with pytest.raises(ValidationError) as exc:
ProductCreateIn(
product_name="t_产品",
product_category="municipal_water",
sale_price="1.23456",
)
assert "最多四位小数" in str(exc.value)
def test_超容量拒绝(self) -> None:
"""DECIMAL(14,4) 整数部分 10 位:超出即拒绝而非溢出 500。"""
with pytest.raises(ValidationError):
ProductCreateIn(
product_name="t_产品",
product_category="municipal_water",
sale_price="99999999999.0000",
)
def test_空串归一None_负数拒绝(self) -> None:
empty = ProductCreateIn(
product_name="t_产品", product_category="municipal_water", sale_price=""
)
assert empty.sale_price is None
with pytest.raises(ValidationError):
ProductCreateIn(
product_name="t_产品", product_category="municipal_water", sale_price="-1"
)
class TestStockQuantity:
"""数量校验:默认 scale=2 对齐 Numeric(14,2) 列。"""
def test_三位小数拒绝(self) -> None:
with pytest.raises(ValidationError):
ProductCreateIn(
product_name="t_产品",
product_category="municipal_water",
stock_quantity="1.001",
)
def test_两位小数通过(self) -> None:
body = ProductCreateIn(
product_name="t_产品",
product_category="municipal_water",
stock_quantity="1.55",
)
assert body.stock_quantity == "1.55"