refactor(battlepass): route premium-buy crystal spend through CurrencySpendService
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -23,19 +23,22 @@ public sealed class BattlePassService : IBattlePassService
|
|||||||
private readonly TimeProvider _time;
|
private readonly TimeProvider _time;
|
||||||
private readonly SVSimDbContext _db;
|
private readonly SVSimDbContext _db;
|
||||||
private readonly RewardGrantService _rewards;
|
private readonly RewardGrantService _rewards;
|
||||||
|
private readonly ICurrencySpendService _spend;
|
||||||
|
|
||||||
public BattlePassService(
|
public BattlePassService(
|
||||||
IBattlePassRepository bp,
|
IBattlePassRepository bp,
|
||||||
IViewerBattlePassRepository viewerBp,
|
IViewerBattlePassRepository viewerBp,
|
||||||
TimeProvider time,
|
TimeProvider time,
|
||||||
SVSimDbContext db,
|
SVSimDbContext db,
|
||||||
RewardGrantService rewards)
|
RewardGrantService rewards,
|
||||||
|
ICurrencySpendService spend)
|
||||||
{
|
{
|
||||||
_bp = bp;
|
_bp = bp;
|
||||||
_viewerBp = viewerBp;
|
_viewerBp = viewerBp;
|
||||||
_time = time;
|
_time = time;
|
||||||
_db = db;
|
_db = db;
|
||||||
_rewards = rewards;
|
_rewards = rewards;
|
||||||
|
_spend = spend;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IReadOnlyDictionary<string, BattlePassLevel>?> GetLevelCurveAsync(CancellationToken ct)
|
public async Task<IReadOnlyDictionary<string, BattlePassLevel>?> GetLevelCurveAsync(CancellationToken ct)
|
||||||
@@ -166,13 +169,13 @@ public sealed class BattlePassService : IBattlePassService
|
|||||||
if (progress.IsPremium)
|
if (progress.IsPremium)
|
||||||
return new BattlePassBuyOutcome(23, Array.Empty<GrantedReward>(), Array.Empty<GrantedReward>());
|
return new BattlePassBuyOutcome(23, Array.Empty<GrantedReward>(), Array.Empty<GrantedReward>());
|
||||||
|
|
||||||
if (viewer.Currency.Crystals < (ulong)season.PriceCrystal)
|
var spendResult = await _spend.TrySpendAsync(viewer, SpendCurrency.Crystal, season.PriceCrystal, ct);
|
||||||
|
if (!spendResult.Success)
|
||||||
return new BattlePassBuyOutcome(22, Array.Empty<GrantedReward>(), Array.Empty<GrantedReward>());
|
return new BattlePassBuyOutcome(22, Array.Empty<GrantedReward>(), Array.Empty<GrantedReward>());
|
||||||
|
|
||||||
// BeginTransactionAsync is a no-op on the SQLite in-memory test DB but is safe to call.
|
// BeginTransactionAsync is a no-op on the SQLite in-memory test DB but is safe to call.
|
||||||
await using var tx = await _db.Database.BeginTransactionAsync(ct);
|
await using var tx = await _db.Database.BeginTransactionAsync(ct);
|
||||||
|
|
||||||
viewer.Currency.Crystals -= (ulong)season.PriceCrystal;
|
|
||||||
progress.IsPremium = true;
|
progress.IsPremium = true;
|
||||||
|
|
||||||
// Retroactive grants: every premium reward at level <= current_level not already claimed.
|
// Retroactive grants: every premium reward at level <= current_level not already claimed.
|
||||||
@@ -206,7 +209,7 @@ public sealed class BattlePassService : IBattlePassService
|
|||||||
// append the post-deduction total so the client gets the correct final balance.
|
// append the post-deduction total so the client gets the correct final balance.
|
||||||
postState.RemoveAll(r => r.RewardType == (int)UserGoodsType.Crystal);
|
postState.RemoveAll(r => r.RewardType == (int)UserGoodsType.Crystal);
|
||||||
postState.Add(new GrantedReward(
|
postState.Add(new GrantedReward(
|
||||||
(int)UserGoodsType.Crystal, 0, (int)viewer.Currency.Crystals));
|
(int)UserGoodsType.Crystal, 0, (int)spendResult.PostStateTotal));
|
||||||
|
|
||||||
return new BattlePassBuyOutcome(1, achieved, postState);
|
return new BattlePassBuyOutcome(1, achieved, postState);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user