fix(wallet): 修复余额不足后重复消费

- 有限钱包结算允许扣成负数,先扣充值余额再扣赠送余额,缺口回写到充值余额
- 日额度钱包补扣路径在存在钱包时不再把余额不足标成 insufficient_quota
- 补充内存和 SQLite 结算回归覆盖,三种数据库实现保持一致
验证:
- cargo fmt --all --check
- cargo clippy -p aether-data --all-targets -- -D warnings
- cargo clippy -p aether-gateway --all-targets -- -D warnings
- cargo clippy --workspace --exclude aether-gateway --exclude aether-data --all-targets -- -D warnings
- cargo nextest run -p aether-gateway
- cargo nextest run -p aether-data
- cargo nextest run --workspace --exclude aether-gateway --exclude aether-data
- cargo test -p aether-data sqlite --lib
- Postgres/MySQL data_db_smoke commands from rust-ci.yml
This commit is contained in:
Entropy.Xu
2026-05-19 19:29:22 +08:00
parent 1b570daf72
commit 7ace958710
5 changed files with 90 additions and 48 deletions
@@ -312,6 +312,7 @@ async fn consume_daily_quota_postgres(
request_id: &str,
total_cost_usd: f64,
wallet_available_usd: Option<f64>,
wallet_can_overdraft: bool,
) -> Result<DailyQuotaDebitResult, DataLayerError> {
if total_cost_usd <= 0.0 {
return Ok(DailyQuotaDebitResult::default());
@@ -379,6 +380,7 @@ WHERE user_entitlement_id = $1
});
}
if allow_wallet_overage
&& !wallet_can_overdraft
&& wallet_available_usd.is_some_and(|available| {
total_remaining + available + SETTLEMENT_EPSILON_USD < total_cost_usd
})
@@ -560,6 +562,7 @@ LIMIT 1
None
};
let wallet_can_overdraft = wallet_row.is_some();
let wallet_available_usd = match wallet_row.as_ref() {
Some(row) => {
let limit_mode: String =
@@ -600,6 +603,7 @@ LIMIT 1
&input.request_id,
input.total_cost_usd,
wallet_available_usd,
wallet_can_overdraft,
)
.await?;
if quota.insufficient {
@@ -646,16 +650,8 @@ LIMIT 1
before_gift,
wallet_debit_cost_usd,
);
if debit_plan.covered_usd() + SETTLEMENT_EPSILON_USD
< wallet_debit_cost_usd
{
final_billing_status = "insufficient_quota".to_string();
settlement.billing_status = final_billing_status.clone();
} else {
after_recharge =
before_recharge - debit_plan.recharge_deduction;
after_gift = before_gift - debit_plan.gift_deduction;
}
(after_recharge, after_gift) =
debit_plan.after_balances(before_recharge, before_gift);
}
if final_billing_status == "settled" {
sqlx::query(