fix(会员计价): 升级报价拒绝到期日早于刷新日的入参

- validate_runtime_profile_membership_upgrade_quote_input 增加 expires_at >= cycle_resets_at 校验,避免回显早于下次刷新日的到期时间。
- 补充到期时刻早于本期刷新时刻的回归断言,并更新函数文档说明。
This commit is contained in:
2026-10-03 17:33:23 +08:00
parent 1811b2206f
commit 1d2574a43f
@@ -143,6 +143,9 @@ pub fn check_runtime_profile_membership_upgrade_allowed(
/// 期号是同一期账期的两个口径,账期已刷新仍按旧 `cycle_index` 报价会多收整整一个完整月
/// (年付还会把补点算成 0)。生产入口先用 `project_profile_membership_cycle_at` 把会员行
/// 投射到当前账期,因此这里拒绝的只会是「拿过期账期直接报价」的错误调用方。
///
/// 到期时刻不能早于本期刷新时刻(`expires_at >= cycle_resets_at`):账期刷新的前提是会员仍在
/// 有效期内,否则报价会回显一个早于下次刷新日的到期时间,得到自相矛盾的结果。
fn validate_runtime_profile_membership_upgrade_quote_input(
input: &RuntimeProfileMembershipUpgradeQuoteInput,
) -> Result<(), RuntimeProfileMembershipUpgradeRejection> {
@@ -151,7 +154,9 @@ fn validate_runtime_profile_membership_upgrade_quote_input(
let window_out_of_order = input.cycle_resets_at_micros <= input.cycle_started_at_micros;
let now_outside_window = input.now_micros < input.cycle_started_at_micros
|| input.now_micros >= input.cycle_resets_at_micros;
if cycle_index_out_of_range || window_out_of_order || now_outside_window {
let expiry_out_of_order = input.expires_at_micros < input.cycle_resets_at_micros;
if cycle_index_out_of_range || window_out_of_order || now_outside_window || expiry_out_of_order
{
return Err(RuntimeProfileMembershipUpgradeRejection::InvalidQuoteInput);
}
Ok(())
@@ -453,6 +458,14 @@ mod tests {
}),
Err(RuntimeProfileMembershipUpgradeRejection::InvalidQuoteInput)
);
// 中文注释:到期时刻早于本期刷新时刻属于自相矛盾的入参,必须显式拒绝。
assert_eq!(
quote_runtime_profile_membership_upgrade(RuntimeProfileMembershipUpgradeQuoteInput {
expires_at_micros: beijing(2026, 7, 1, 9),
..base_input()
}),
Err(RuntimeProfileMembershipUpgradeRejection::InvalidQuoteInput)
);
}
#[test]