大量优化修改扣积分规则

This commit is contained in:
Azmat@qq.com
2026-09-04 17:20:22 +08:00
parent 3e904479d9
commit 15718a60bf
41 changed files with 1590 additions and 429 deletions
+93
View File
@@ -487,3 +487,96 @@ class TeamPriceMultiplierTests(TestCase):
client = APIClient()
client.force_authenticate(self.user)
self.assertEqual(client.get("/api/billing/config/").json()["team_price_multiplier"], "0.80")
class ListedPointsPricingTests(TestCase):
"""老板挂牌秒价:预留精确、结算认快照,不跟 tokens/中途改价跑偏。"""
def setUp(self):
from apps.billing.pricing import invalidate_billing_config_cache
invalidate_billing_config_cache()
self.user = User.objects.create_user(username="listed-pts", password="p")
self.team = Team.objects.create(name="listed", owner=self.user, price_multiplier=Decimal("1.00"))
TeamMember.objects.create(team=self.team, user=self.user, role=TeamMember.Role.OWNER)
CreditAccount.objects.create(team=self.team, balance=Decimal("10000"), reserved_balance=Decimal("0"))
provider, _ = ModelProvider.objects.get_or_create(name="volcengine", defaults={"display_name": "V"})
self.model = ModelConfig.objects.create(
provider=provider,
name="doubao-seedance-listed",
display_name="Listed Mini",
capability=ModelConfig.Capability.VIDEO,
unit_price=Decimal("0"),
status=ModelConfig.Status.ACTIVE,
metadata={
"capabilities": {"resolutions": ["480p", "720p"], "durations": [4, 5]},
"points_pricing": {
"mode": "per_second",
"tiers": [
{"resolution": "720p", "points_per_second": 10, "points_per_second_with_ref": 15},
{"resolution": "480p", "points_per_second": 6},
],
},
},
)
def test_estimate_and_exact_reserve(self):
from apps.billing.pricing import quote_video_estimate, video_reserve_amount
_tokens, quote = quote_video_estimate(
self.model, aspect_ratio="16:9", resolution="720p", duration=5, references=[], team=self.team,
)
self.assertEqual(quote.meta["rule"], "points_per_second")
self.assertEqual(quote.points, Decimal("50")) # 10 * 5
self.assertEqual(video_reserve_amount(quote.points, rule=quote.meta["rule"]), Decimal("50"))
# token 路径仍乘 buffer(默认 1.10)
self.assertEqual(video_reserve_amount(Decimal("50"), rule="video_tokens"), Decimal("55"))
def test_settle_snapshot_ignores_model_price_change_and_tokens(self):
from apps.billing.pricing import quote_video_estimate, settle_video_from_payload, video_quote_payload
_tokens, quote = quote_video_estimate(
self.model,
aspect_ratio="16:9",
resolution="720p",
duration=5,
references=[{"type": "video", "url": "http://x"}],
team=self.team,
)
# 含视频参考 → 15 * 5 = 75
self.assertEqual(quote.points, Decimal("75"))
payload = {
"resolution": "720p",
"duration": 5,
**video_quote_payload(quote),
"references": [{"type": "video"}],
}
# 中途把挂牌改成天价
meta = dict(self.model.metadata)
meta["points_pricing"] = {
"mode": "per_second",
"tiers": [{"resolution": "720p", "points_per_second": 999, "points_per_second_with_ref": 999}],
}
self.model.metadata = meta
self.model.save(update_fields=["metadata"])
settle = settle_video_from_payload(self.model, payload=payload, tokens=9_999_999)
self.assertEqual(settle.points, Decimal("75"))
self.assertEqual(settle.meta["rule"], "points_per_second")
settle0 = settle_video_from_payload(self.model, payload=payload, tokens=0)
self.assertEqual(settle0.points, Decimal("75"))
def test_flat_image_uses_points_per_image(self):
from apps.billing.pricing import quote_flat
provider, _ = ModelProvider.objects.get_or_create(name="volcengine", defaults={"display_name": "V"})
image = ModelConfig.objects.create(
provider=provider,
name="seedream-listed",
capability=ModelConfig.Capability.IMAGE,
unit_price=Decimal("0"),
status=ModelConfig.Status.ACTIVE,
metadata={"points_pricing": {"mode": "per_image", "points_per_image": 33}},
)
quote = quote_flat(image, units=2, team=self.team)
self.assertEqual(quote.points, Decimal("66"))
self.assertEqual(quote.meta.get("rule"), "per_image")