refactor(itempurchase): route currency spend (not items) through CurrencySpendService
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -23,12 +23,14 @@ public class ItemPurchaseController : SVSimController
|
||||
private readonly SVSimDbContext _db;
|
||||
private readonly RewardGrantService _rewards;
|
||||
private readonly TimeProvider _time;
|
||||
private readonly ICurrencySpendService _spend;
|
||||
|
||||
public ItemPurchaseController(SVSimDbContext db, RewardGrantService rewards, TimeProvider time)
|
||||
public ItemPurchaseController(SVSimDbContext db, RewardGrantService rewards, TimeProvider time, ICurrencySpendService spend)
|
||||
{
|
||||
_db = db;
|
||||
_rewards = rewards;
|
||||
_time = time;
|
||||
_spend = spend;
|
||||
}
|
||||
|
||||
[HttpPost("info")]
|
||||
@@ -117,7 +119,7 @@ public class ItemPurchaseController : SVSimController
|
||||
var rewardList = new List<RewardListEntry>();
|
||||
|
||||
// Debit the require side. RewardGrantService is grant-only, so handle this inline.
|
||||
var debit = TryDebit(viewer, (UserGoodsType)entry.RequireItemType, entry.RequireItemId, entry.RequireItemNum);
|
||||
var debit = await TryDebit(viewer, (UserGoodsType)entry.RequireItemType, entry.RequireItemId, entry.RequireItemNum);
|
||||
if (debit.Error is not null) return BadRequest(new { error = debit.Error });
|
||||
if (debit.PostState is not null) rewardList.Add(debit.PostState);
|
||||
|
||||
@@ -160,29 +162,29 @@ public class ItemPurchaseController : SVSimController
|
||||
/// from the viewer, returning a post-state-aware <see cref="RewardListEntry"/> the client
|
||||
/// uses to refresh its cached count. Returns an error string on insufficient balance.
|
||||
/// </summary>
|
||||
private static (RewardListEntry? PostState, string? Error) TryDebit(
|
||||
private async Task<(RewardListEntry? PostState, string? Error)> TryDebit(
|
||||
Viewer viewer, UserGoodsType type, long detailId, int num)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case UserGoodsType.RedEther:
|
||||
if (viewer.Currency.RedEther < (ulong)num)
|
||||
return (null, "insufficient_red_ether");
|
||||
viewer.Currency.RedEther -= (ulong)num;
|
||||
return (new RewardListEntry { RewardType = 1, RewardId = 0, RewardNum = (int)viewer.Currency.RedEther }, null);
|
||||
|
||||
{
|
||||
var r = await _spend.TrySpendAsync(viewer, SpendCurrency.RedEther, num);
|
||||
if (!r.Success) return (null, "insufficient_red_ether");
|
||||
return (new RewardListEntry { RewardType = 1, RewardId = 0, RewardNum = (int)r.PostStateTotal }, null);
|
||||
}
|
||||
case UserGoodsType.Crystal:
|
||||
if (viewer.Currency.Crystals < (ulong)num)
|
||||
return (null, "insufficient_crystals");
|
||||
viewer.Currency.Crystals -= (ulong)num;
|
||||
return (new RewardListEntry { RewardType = 2, RewardId = 0, RewardNum = (int)viewer.Currency.Crystals }, null);
|
||||
|
||||
{
|
||||
var r = await _spend.TrySpendAsync(viewer, SpendCurrency.Crystal, num);
|
||||
if (!r.Success) return (null, "insufficient_crystals");
|
||||
return (new RewardListEntry { RewardType = 2, RewardId = 0, RewardNum = (int)r.PostStateTotal }, null);
|
||||
}
|
||||
case UserGoodsType.Rupy:
|
||||
if (viewer.Currency.Rupees < (ulong)num)
|
||||
return (null, "insufficient_rupees");
|
||||
viewer.Currency.Rupees -= (ulong)num;
|
||||
return (new RewardListEntry { RewardType = 9, RewardId = 0, RewardNum = (int)viewer.Currency.Rupees }, null);
|
||||
|
||||
{
|
||||
var r = await _spend.TrySpendAsync(viewer, SpendCurrency.Rupee, num);
|
||||
if (!r.Success) return (null, "insufficient_rupees");
|
||||
return (new RewardListEntry { RewardType = 9, RewardId = 0, RewardNum = (int)r.PostStateTotal }, null);
|
||||
}
|
||||
case UserGoodsType.Item:
|
||||
var owned = viewer.Items.FirstOrDefault(i => i.Item.Id == (int)detailId);
|
||||
if (owned is null || owned.Count < num)
|
||||
|
||||
Reference in New Issue
Block a user