写入Tripo 3D泥点默认价并锁定credit换算口径
- 受控默认配置新增 model3d 段:底价按端点 × 模型版本 × 是否有贴图,add-on 六项独立计价 - 换算口径固定为泥点 = ceil(0.8 × Tripo 官方 credit),H 系列 10/20 与 20/30、P1 30/40 与 40/50、P2 100/110 - editor_generation_config 定向用例按 credit 表反算默认泥点价,改价必须先改 credit 表 - 段缺失语义改为显式摘段验证,仍保持 fail closed 不扣费不入队 - 主规范、里程碑、实施计划与定价管理方案同步默认价已确认与部署侧 override 风险
This commit is contained in:
@@ -663,7 +663,8 @@ mod tests {
|
||||
};
|
||||
|
||||
use crate::tripo3d::pricing::{
|
||||
Model3dAddOn, Model3dEndpoint, Model3dPricingError, Model3dPricingQuery, model3d_add_ons,
|
||||
Model3dAddOn, Model3dAddOnSet, Model3dEndpoint, Model3dPricingError, Model3dPricingQuery,
|
||||
model3d_add_ons,
|
||||
};
|
||||
|
||||
/// 最小完整 3D 价格段:每个模型版本两个端点 × 两种贴图态 + 全部 add-on。
|
||||
@@ -717,14 +718,26 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn editor_generation_pricing_keeps_model3d_optional_until_configured() {
|
||||
let config = default_runtime_pricing();
|
||||
/// Tripo 官方 credit → 泥点的换算系数:泥点 = `ceil(系数 × credit)`。
|
||||
const MODEL3D_CREDIT_TO_MUD_FACTOR: f64 = 0.8;
|
||||
|
||||
assert!(
|
||||
config.model3d.is_none(),
|
||||
"业务给出数值前,受控默认配置不带 3D 定价段"
|
||||
);
|
||||
fn mud_from_credit(credit: u32) -> u32 {
|
||||
(f64::from(credit) * MODEL3D_CREDIT_TO_MUD_FACTOR).ceil() as u32
|
||||
}
|
||||
|
||||
/// `model3d` 段缺失是合法形态,代表 3D 定价尚未配置:查价必须失败关闭,不扣费。
|
||||
/// 受控默认配置现在带真实数值,所以这里显式摘掉该段来验证缺失语义。
|
||||
#[test]
|
||||
fn editor_generation_pricing_fails_closed_when_model3d_section_is_absent() {
|
||||
let mut json: Value =
|
||||
serde_json::from_str(EDITOR_GENERATION_PRICING_DEFAULT_JSON).expect("默认配置是 JSON");
|
||||
json.as_object_mut()
|
||||
.expect("默认配置应是对象")
|
||||
.remove("model3d");
|
||||
let config = parse_editor_generation_pricing_json(&json.to_string(), "测试配置")
|
||||
.expect("缺少 3D 段仍应可加载");
|
||||
|
||||
assert!(config.model3d.is_none());
|
||||
let error = config
|
||||
.model3d_price(&query(
|
||||
false,
|
||||
@@ -741,6 +754,118 @@ mod tests {
|
||||
assert_eq!(error, Model3dPricingError::NotConfigured);
|
||||
}
|
||||
|
||||
/// 受控默认配置里的 3D 泥点价必须严格等于 `ceil(0.8 × Tripo 官方 credit)`:
|
||||
/// 底价按「端点 × 模型版本 × 是否有贴图」,add-on 按项叠加。改价必须先改这里的
|
||||
/// credit 表,否则这条断言会失败,避免默认价脱离已确认的换算口径。
|
||||
#[test]
|
||||
fn default_model3d_prices_convert_tripo_credits_at_configured_factor() {
|
||||
let config = default_runtime_pricing();
|
||||
let model3d = config.model3d.as_ref().expect("默认配置必须带 3D 定价段");
|
||||
|
||||
// (端点, 模型版本, 无贴图 credit, 带贴图 credit)
|
||||
let base_credits = [
|
||||
(
|
||||
Model3dEndpoint::TextToModel,
|
||||
Model3dModelVersion::H31,
|
||||
10,
|
||||
20,
|
||||
),
|
||||
(
|
||||
Model3dEndpoint::TextToModel,
|
||||
Model3dModelVersion::H30,
|
||||
10,
|
||||
20,
|
||||
),
|
||||
(
|
||||
Model3dEndpoint::TextToModel,
|
||||
Model3dModelVersion::H25,
|
||||
10,
|
||||
20,
|
||||
),
|
||||
(
|
||||
Model3dEndpoint::TextToModel,
|
||||
Model3dModelVersion::P1,
|
||||
30,
|
||||
40,
|
||||
),
|
||||
(
|
||||
Model3dEndpoint::TextToModel,
|
||||
Model3dModelVersion::P2,
|
||||
100,
|
||||
110,
|
||||
),
|
||||
(
|
||||
Model3dEndpoint::ImageToModel,
|
||||
Model3dModelVersion::H31,
|
||||
20,
|
||||
30,
|
||||
),
|
||||
(
|
||||
Model3dEndpoint::ImageToModel,
|
||||
Model3dModelVersion::H30,
|
||||
20,
|
||||
30,
|
||||
),
|
||||
(
|
||||
Model3dEndpoint::ImageToModel,
|
||||
Model3dModelVersion::H25,
|
||||
20,
|
||||
30,
|
||||
),
|
||||
(
|
||||
Model3dEndpoint::ImageToModel,
|
||||
Model3dModelVersion::P1,
|
||||
40,
|
||||
50,
|
||||
),
|
||||
(
|
||||
Model3dEndpoint::ImageToModel,
|
||||
Model3dModelVersion::P2,
|
||||
100,
|
||||
110,
|
||||
),
|
||||
];
|
||||
for (endpoint, model_version, no_texture_credit, texture_credit) in base_credits {
|
||||
for (texture, credit) in [(false, no_texture_credit), (true, texture_credit)] {
|
||||
let price = config
|
||||
.model3d_price(&Model3dPricingQuery {
|
||||
endpoint,
|
||||
model_version,
|
||||
texture,
|
||||
add_ons: Model3dAddOnSet::default(),
|
||||
})
|
||||
.expect("默认配置必须能查出底价");
|
||||
assert_eq!(
|
||||
price,
|
||||
mud_from_credit(credit),
|
||||
"{} {model_version:?} texture={texture} 的底价应为 ceil(0.8 × {credit}) 泥点",
|
||||
endpoint.as_str(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let add_on_credits = [
|
||||
(Model3dAddOn::HdTexture, 10),
|
||||
(Model3dAddOn::UltraTexture, 20),
|
||||
(Model3dAddOn::HdGeometry, 20),
|
||||
(Model3dAddOn::QuadMesh, 5),
|
||||
(Model3dAddOn::SmartLowPoly, 10),
|
||||
(Model3dAddOn::GenerateParts, 20),
|
||||
];
|
||||
for (add_on, credit) in add_on_credits {
|
||||
let price = model3d
|
||||
.add_on_prices
|
||||
.get(&add_on)
|
||||
.copied()
|
||||
.unwrap_or_else(|| panic!("默认配置缺少 {add_on:?} 的价格"));
|
||||
assert_eq!(
|
||||
price,
|
||||
mud_from_credit(credit),
|
||||
"{add_on:?} 的加价应为 ceil(0.8 × {credit}) 泥点"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn editor_generation_pricing_validates_model3d_section_when_present() {
|
||||
let json = pricing_json_with_model3d(model3d_pricing_json());
|
||||
|
||||
Reference in New Issue
Block a user