修复(计费): 升级报价总期数改由周期类型推导
- 删除 RuntimeProfileMembershipUpgradeQuoteInput.cycle_count 入参,改由 target.cycle_kind.cycle_count() 推导(月付 1 / 年付 12),杜绝入参期数与周期类型不一致导致按错误期数计费 - 报价数值自检的期号上界改为相对推导出的总期数判断 - spacetime-module 构造报价入参时不再传 cycle_count - 同步升级报价单测:年付 12 期、当前第 3 期 → 剩余完整月数 9,金额与测试夹具一并修正 - 同步设计文档 §3 入参与自检说明、§5.3 年付示例(remainingFullMonths 9 / amountCents 158334) Co-authored-by: Junie <junie@jetbrains.com>
This commit is contained in:
@@ -271,15 +271,17 @@ pub struct RuntimeProfileMembershipUpgradeQuote {
|
||||
`beijing_local_micros(年月日, 当日微秒)`、`membership_expires_at(anchor, cycle_kind)`、
|
||||
`membership_cycle_remaining_micros(resets_at, now)`。
|
||||
- `quote_runtime_profile_membership_upgrade(input) -> Result<quote, rejection>`:
|
||||
入参 `RuntimeProfileMembershipUpgradeQuoteInput`(当前档位 / 周期、目标档位 / 周期、期序号 / 期总数、
|
||||
入参 `RuntimeProfileMembershipUpgradeQuoteInput`(当前档位 / 周期、目标档位 / 周期、期序号、
|
||||
本期窗口、当前月度余额、`now`);金额向上取到分、补点向下取整;月付 / 年付分支见 §6;年价取目录 `year_price_cents`。
|
||||
- 报价函数对数值入参做防御式自检:`1 <= cycle_index <= cycle_count`、`cycle_started_at <= now`、
|
||||
`cycle_started_at <= cycle_resets_at`,越界返回 `invalid_quote_input`(`InvalidQuoteInput`),
|
||||
不再被 `saturating_sub` 静默夹取;生产入口从会员行构造的入参恒满足这些不变量。
|
||||
本次购买总期数**不是入参**:由目标周期类型推导(`target.cycle_kind.cycle_count()`,月付 1 / 年付 12),
|
||||
杜绝「入参期数与周期类型不一致」导致按错误期数计费。
|
||||
- 报价函数对数值入参做防御式自检:`1 <= cycle_index <= cycle_count`(`cycle_count` 由上一步推导)、
|
||||
`cycle_started_at <= now`、`cycle_started_at <= cycle_resets_at`,越界返回 `invalid_quote_input`
|
||||
(`InvalidQuoteInput`),不再被 `saturating_sub` 静默夹取;生产入口从会员行构造的入参恒满足这些不变量。
|
||||
- `check_runtime_profile_membership_upgrade_allowed(...) -> Result<(), rejection>`:
|
||||
§3.4 允许操作矩阵的唯一实现(非会员不可升级 / 不支持月转年与年转月 / 同档与降档拒绝 / 目标不可购买拒绝)。
|
||||
- `membership_cycle_remaining_ratio_ppm(cycle_started_at, cycle_resets_at, now) -> u32`:本期剩余比例(ppm,向下取整)。
|
||||
- **「后续完整月数」= `cycle_count − cycle_index`**,不从 `cycle_resets_at` 重新锚定推算:
|
||||
- **「后续完整月数」= `cycle_count − cycle_index`**(`cycle_count` 由周期类型推导),不从 `cycle_resets_at` 重新锚定推算:
|
||||
月末夹取后的日期(1/31 锚点得到 2/28)不再是原始开通日,重锚会把后续月份漂移成 3/28。
|
||||
- `apply_membership_upgrade(row, quote) -> row'`:`cycle_remaining += 补点`、
|
||||
`cycle_granted_points += 补点`、`plan` 更新,刷新日与到期日不变。
|
||||
@@ -365,12 +367,12 @@ flowchart TD
|
||||
"cycleKind": "yearly",
|
||||
"cycleIndex": 3,
|
||||
"cycleCount": 12,
|
||||
"amountCents": 108334,
|
||||
"amountCents": 158334,
|
||||
"grantedPointsDelta": 1250,
|
||||
"monthlyBalanceAfter": 1865,
|
||||
"expiresAt": "...",
|
||||
"cycleResetsAt": "...",
|
||||
"remainingFullMonths": 6
|
||||
"remainingFullMonths": 9
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user