fix(billing): make quota seed and column names match the product SSOT

The product plan is the only source for quota numbers, but the 0001 seed
used a second set (agent_chat 20/50, tryon hard 10) and omitted hairstyle,
hd_export and report regen. Migration 0003 replaces the seed and renames
points_reserved → quota_reserved and bonus_value → bonus_granted so the
docs and the schema stop contradicting each other.

Effective limit now clips at hard_cap. CI runs the integration slice
against the Postgres/Redis services it already starts.
This commit is contained in:
xsl
2026-08-14 11:28:35 +08:00
parent c97f8ae3e1
commit 2009aa938c
11 changed files with 179 additions and 16 deletions
+1 -1
View File
@@ -38,7 +38,7 @@ async def lock_or_create_quota(
period_key=period_key,
used=0,
limit_value=limit_value,
bonus_value=0,
bonus_granted=0,
)
.on_conflict_do_nothing(index_elements=["user_id", "quota_key", "period_key"])
)
+14 -5
View File
@@ -44,7 +44,7 @@ class QuotaSnapshot:
period_key: str
used: int
limit_value: int
bonus_value: int
bonus_granted: int
remaining: int
reset_at: datetime | None
@@ -69,14 +69,17 @@ class BillingService:
limit_value=rule.base_limit,
)
state = quota_rules.QuotaState(
used=row.used, base_limit=row.limit_value, bonus=row.bonus_value
used=row.used,
base_limit=row.limit_value,
bonus=row.bonus_granted,
hard_cap=rule.hard_cap,
)
return QuotaSnapshot(
quota_key=quota_key,
period_key=period_key,
used=row.used,
limit_value=row.limit_value,
bonus_value=row.bonus_value,
bonus_granted=row.bonus_granted,
remaining=state.remaining,
reset_at=quota_rules.period_reset_at(now, period_type, self._tz_offset),
)
@@ -126,7 +129,10 @@ class BillingService:
limit_value=rule.base_limit,
)
state = quota_rules.QuotaState(
used=row.used, base_limit=row.limit_value, bonus=row.bonus_value
used=row.used,
base_limit=row.limit_value,
bonus=row.bonus_granted,
hard_cap=rule.hard_cap,
)
try:
@@ -222,7 +228,10 @@ class BillingService:
limit_value=rule.base_limit,
)
state = quota_rules.QuotaState(
used=row.used, base_limit=row.limit_value, bonus=row.bonus_value
used=row.used,
base_limit=row.limit_value,
bonus=row.bonus_granted,
hard_cap=rule.hard_cap,
)
new_state = quota_rules.refund(state, reservation.amount)
row.used = new_state.used