3D 查价的加价累加改成溢出即报错

- server-rs/crates/api-server/src/tripo3d/pricing.rs:endpoint 查价用 checked_add 替换 saturating_add,溢出走新的 Model3dPricingError::PriceOverflow,与加载校验的 fail-closed 口径一致,不再静默夹到 u32 上限按错价收费
- server-rs/crates/api-server/src/tripo3d/pricing.rs:补用例锁住「底价 + 加价项溢出必须报错」
This commit is contained in:
2026-09-24 17:55:12 +08:00
parent 98f2c21872
commit f82eba4c94
@@ -208,6 +208,8 @@ pub(crate) enum Model3dPricingError {
MissingAddOnPrice(Model3dAddOn),
/// `texture=false` 却带上贴图类加价项:组合自相矛盾,直接报错而不是照价收费。
InconsistentTextureAddOn(Model3dAddOn),
/// 底价 + 加价项累加超出 `u32`:配置阶段已挡过一次,这里是计费点的第二道闸。
PriceOverflow,
}
impl std::fmt::Display for Model3dPricingError {
@@ -230,6 +232,7 @@ impl std::fmt::Display for Model3dPricingError {
f,
"Tripo 3D 定价组合不合法:texture=false 与贴图类 add-on {add_on:?} 冲突"
),
Self::PriceOverflow => f.write_str("Tripo 3D 定价加总超出 u32 上限"),
}
}
}
@@ -327,10 +330,14 @@ impl Model3dEndpointPricing {
.add_ons
.iter()
.try_fold(base.for_texture(query.texture), |total, add_on| {
self.add_on_prices
let price = self
.add_on_prices
.get(&add_on)
.map(|price| total.saturating_add(*price))
.ok_or(Model3dPricingError::MissingAddOnPrice(add_on))
.ok_or(Model3dPricingError::MissingAddOnPrice(add_on))?;
// 与加载校验口径一致:溢出就报错退款,不静默夹到 u32 上限后按错价收费。
total
.checked_add(*price)
.ok_or(Model3dPricingError::PriceOverflow)
})
}
}
@@ -439,6 +446,29 @@ mod tests {
);
}
#[test]
fn price_overflow_fails_closed_instead_of_clamping() {
let mut pricing = sample_endpoint_pricing(10, 20);
pricing
.add_on_prices
.insert(Model3dAddOn::HdGeometry, u32::MAX);
pricing.add_on_prices.insert(Model3dAddOn::QuadMesh, 1);
let query = text_query(
false,
Model3dAddOnSet {
hd_geometry: true,
quad_mesh: true,
..Model3dAddOnSet::default()
},
);
assert_eq!(
pricing.price(&query),
Err(Model3dPricingError::PriceOverflow)
);
}
#[test]
fn texture_add_ons_without_texture_are_rejected() {
let config = sample_config();